/**
 * @file   RegistrationRequestPacket.cpp
 * @author Djuro Drljaca (djurodrljaca@gmail.com)
 * @date   2014-04-21
 * @brief  DON packet object: Registration Request
 *
 * Copyright 2014  Djuro Drljaca (djurodrljaca@gmail.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <DON/Core/Packet/RegistrationRequestPacket.h>
#include <DON/Core/Packet/GenericPacket.h>
#include <DON/Core/DataType/UInt8.h>
#include <DON/Core/DataType/UInt16.h>
#include <DON/Core/DataType/Structure.h>
#include <QtCore/QByteArray>

using namespace DON::Core::Packet;
using namespace DON::Core::DataType;
using namespace DON::Core::Node;

class RegistrationRequestPacket::Private
{
public:
    Private()
        : addressCount(0u),
          communicationMode(CommunicationMode_Invalid),
          maxPayloadLength(0u)
    { }

    quint16 addressCount;
    CommunicationMode communicationMode;
    quint16 maxPayloadLength;
};

RegistrationRequestPacket::RegistrationRequestPacket()
    : AbstractPacket(),
      d(new Private())
{
    setPacketType(PacketType_RegistrationRequest);
}

RegistrationRequestPacket::RegistrationRequestPacket(const quint16 source,
                                                     const quint16 destination,
                                                     const quint16 sequence,
                                                     const quint16 addressCount,
                                                     const CommunicationMode communicationMode,
                                                     const quint16 maxPayloadLength)
    : AbstractPacket(source,
                     destination,
                     PacketType_RegistrationRequest,
                     sequence),
      d(new Private())
{
    d->addressCount = addressCount;
    d->communicationMode = communicationMode;
    d->maxPayloadLength = maxPayloadLength;
}

RegistrationRequestPacket::RegistrationRequestPacket(const RegistrationRequestPacket &other)
    : AbstractPacket(other),
      d(new Private())
{
    d->addressCount = other.d->addressCount;
    d->communicationMode = other.d->communicationMode;
    d->maxPayloadLength = other.d->maxPayloadLength;
}

RegistrationRequestPacket::~RegistrationRequestPacket()
{
    delete d;
}

RegistrationRequestPacket & RegistrationRequestPacket::operator=(
        const RegistrationRequestPacket &other)
{
    AbstractPacket::operator=(other);

    d->addressCount = other.d->addressCount;
    d->communicationMode = other.d->communicationMode;
    d->maxPayloadLength = other.d->maxPayloadLength;

    return *this;
}

bool RegistrationRequestPacket::isValid() const
{
    bool valid = false;

    if ((d->addressCount > 0) &&
        (isCommunicationModeValid(d->communicationMode)))
    {
        valid = true;
    }

    return valid;
}

quint16 RegistrationRequestPacket::getAddressCount() const
{
    return d->addressCount;
}

void RegistrationRequestPacket::setAddressCount(const quint16 addressCount)
{
    d->addressCount = addressCount;
}

CommunicationMode RegistrationRequestPacket::getCommunicationMode() const
{
    return d->communicationMode;
}

void RegistrationRequestPacket::setCommunicationMode(const CommunicationMode communicationMode)
{
    d->communicationMode = communicationMode;
}

quint16 RegistrationRequestPacket::getMaxPayloadLength() const
{
    return d->maxPayloadLength;
}

void RegistrationRequestPacket::setMaxPayloadLength(const quint16 maxPayloadLength)
{
    d->maxPayloadLength = maxPayloadLength;
}

RegistrationRequestPacket RegistrationRequestPacket::fromGenericPacket(
        const GenericPacket &genericPacket)
{
    bool success = false;
    RegistrationRequestPacket packet;

    if (genericPacket.isValid() &&
        (genericPacket.getPacketType() == packet.getPacketType()))
    {
        // Parse payload items
        const Structure *payloadItems = genericPacket.getPayloadItems(&success);

        if (success)
        {
            if (payloadItems->getMemberCount() != 3)
            {
                success = false;
            }
        }

        // Address Count
        quint16 addressCount = 0u;

        if (success)
        {
            const AbstractDataType *adt = payloadItems->getMember(0);
            const UInt16 *value = UInt16::fromAbstractDataType(adt);

            if (value != NULL)
            {
                addressCount = value->getValue();
            }
            else
            {
                success = false;
            }
        }

        // Communication Mode
        CommunicationMode communicationMode = CommunicationMode_Invalid;

        if (success)
        {
            const AbstractDataType *adt = payloadItems->getMember(1);
            const UInt8 *value = UInt8::fromAbstractDataType(adt);

            if (value != NULL)
            {
                const char data = static_cast<char>(value->getValue());
                communicationMode = fromBinaryToCommunicationMode(data);

                success = isCommunicationModeValid(communicationMode);
            }
            else
            {
                success = false;
            }
        }

        // Max Payload Length
        quint16 maxPayloadLength = 0u;

        if (success)
        {
            const AbstractDataType *adt = payloadItems->getMember(2);
            const UInt16 *value = UInt16::fromAbstractDataType(adt);

            if (value != NULL)
            {
                maxPayloadLength = value->getValue();
            }
            else
            {
                success = false;
            }
        }

        delete payloadItems;
        payloadItems = NULL;

        // Save values
        if (success)
        {
            packet.setSource(genericPacket.getSource());
            packet.setDestination(genericPacket.getDestination());
            packet.setSequence(genericPacket.getSequence());

            packet.setAddressCount(addressCount);
            packet.setCommunicationMode(communicationMode);
            packet.setMaxPayloadLength(maxPayloadLength);
        }
    }

    return packet;
}

QList<QByteArray> RegistrationRequestPacket::getPayloadDataItems(bool *ok) const
{
    QList<QByteArray> payloadDataItems;
    bool success = false;

    if (isValid())
    {
        success = true;

        // Address Count
        payloadDataItems.append(UInt16::toBinary(d->addressCount));

        // Communication Mode
        const char communicationMode = fromCommunicationModeToBinary(d->communicationMode);
        payloadDataItems.append(QByteArray(1, communicationMode));

        // Max Payload Length
        payloadDataItems.append(UInt16::toBinary(d->maxPayloadLength));
    }

    if (ok != NULL)
    {
        *ok = success;
    }

    return payloadDataItems;
}
